home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / BasicTableHeaderUI.java < prev    next >
Text File  |  1998-06-30  |  16KB  |  526 lines

  1. /*
  2.  * @(#)BasicTableHeaderUI.java    1.31 98/04/08
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21. package com.sun.java.swing.plaf.basic;
  22.  
  23. import com.sun.java.swing.table.*;
  24. import com.sun.java.swing.*;
  25. import com.sun.java.swing.event.*;
  26. import java.util.Enumeration;
  27. import java.awt.event.*;
  28. import java.awt.*;
  29. import com.sun.java.swing.plaf.*;
  30. import java.io.Serializable;
  31.  
  32. /**
  33.  * BasicTableHeaderUI implementation
  34.  * <p>
  35.  * Warning: serialized objects of this class will not be compatible with
  36.  * future swing releases.  The current serialization support is appropriate
  37.  * for short term storage or RMI between Swing1.0 applications.  It will
  38.  * not be possible to load serialized Swing1.0 objects with future releases
  39.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  40.  * baseline for the serialized form of Swing objects.
  41.  *
  42.  * @version 1.31 04/08/98
  43.  * @author Alan Chung
  44.  * @author Philip Milne
  45.  */
  46. public class BasicTableHeaderUI extends TableHeaderUI implements MouseListener,
  47.     MouseMotionListener, FocusListener, Serializable
  48. {
  49.  
  50. //
  51. // Instance Variables
  52. //
  53.  
  54.     /** The JTableHeader this UI is hooked up to */
  55.     protected JTableHeader header;
  56.  
  57.     // cache vars
  58.     protected CellRendererPane rendererPane = new CellRendererPane();
  59.     transient protected int hitColumnIndex;
  60.     transient protected TableColumn hitColumn;
  61.     transient protected boolean isResizing;
  62.     transient protected int originalWidth;
  63.     transient protected int widthDelta;
  64.     transient protected int lastMouseX;
  65.  
  66.     transient protected int realDraggedDistance;
  67.     transient protected boolean isReordering;
  68.     transient protected boolean okToReorder;
  69.     transient protected boolean fireAction;
  70.     transient protected boolean hasPress = false;
  71.  
  72. //
  73. // Install/Deinstall UI
  74. //
  75.  
  76.     public static ComponentUI createUI(JComponent h) {
  77.         return new BasicTableHeaderUI();
  78.     }
  79.  
  80.     public void installUI(JComponent c) {
  81.     header = (JTableHeader)c;
  82.  
  83.     header.add(rendererPane);
  84.  
  85.     c.addMouseListener(this);
  86.         c.addMouseMotionListener(this);
  87.     c.addFocusListener(this);
  88.  
  89.         LookAndFeel.installColorsAndFont(header, "TableHeader.background",
  90.                      "TableHeader.foreground", "TableHeader.font");
  91.     }
  92.  
  93.     public void uninstallUI(JComponent c) {
  94.     header.remove(rendererPane);
  95.  
  96.     header = null;
  97.  
  98.     c.removeMouseListener(this);
  99.         c.removeMouseMotionListener(this);
  100.     c.removeFocusListener(this);
  101.  
  102.  
  103.  
  104.     /*c.resetKeyboardActions();*/
  105.     }
  106.  
  107. //
  108. // MouseListener, MouseMotionListener, FocusListener Methods
  109. //
  110.  
  111.     public void focusGained(FocusEvent e) {}
  112.     public void focusLost(FocusEvent e) {}
  113.  
  114.     static final Cursor defaultCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
  115.     static final Cursor resizeCursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
  116.  
  117.     public void mouseMoved(MouseEvent e) {
  118.     if (getResizingColumn(e.getPoint()) != -1) {
  119.         if (header.getCursor() != resizeCursor)
  120.         header.setCursor(resizeCursor);
  121.     }
  122.     else {
  123.         if (header.getCursor() != defaultCursor)
  124.         header.setCursor(defaultCursor);
  125.     }
  126.     }
  127.  
  128.     public void mouseDragged(MouseEvent e) {
  129.     fireAction = false;
  130.     int mouseX = e.getX();
  131.  
  132.     if (mouseX == lastMouseX)
  133.         return;
  134.  
  135.  
  136.     if (isResizing) {
  137.         widthDelta += mouseX - lastMouseX;
  138.         int newWidth = originalWidth + widthDelta;
  139.         hitColumn.setWidth(newWidth);
  140.             header.revalidate();
  141.             header.repaint();
  142.         if (header.getUpdateTableInRealTime()) {
  143.         JTable table = header.getTable();
  144.                 table.revalidate();
  145.                 table.repaint();
  146.         }
  147.     }
  148.     else if (okToReorder || isReordering) {
  149.         isReordering = true;
  150.         move(e);
  151.     }
  152.     else {
  153.         // Doing a simple drag selection
  154.  
  155.     }
  156.  
  157.     lastMouseX = mouseX;
  158.     }
  159.  
  160.     public void mouseClicked(MouseEvent e) {}
  161.  
  162.     public void mousePressed(MouseEvent e) {
  163.     // PENDING(alan):  For some reason if you do a click drag on the
  164.     // header cell and the cursor moves out of the window mousePressed
  165.     // is called again.  So we check and prevent second entry
  166.     if (hasPress)
  167.         return;
  168.     hasPress = true;
  169.  
  170.  
  171.     TableColumnModel columnModel = header.getColumnModel();
  172.     Rectangle headerRect;
  173.     int index = 0;
  174.  
  175.     // Init cache vars
  176.     isReordering = false;
  177.     isResizing = false;
  178.     fireAction = true;
  179.     hitColumnIndex = -1;
  180.     hitColumn = null;
  181.  
  182.     Point p = e.getPoint();
  183.  
  184.     // First find which header cell was hit
  185.     if ((index = columnModel.getColumnIndexAtX(p.x)) != -1) {
  186.         headerRect = header.getHeaderRect(index);
  187.  
  188.         // The last 3 pixels + 3 pixels of next column are for resizing
  189.         int resizeIndex = getResizingColumn(p);
  190.  
  191.         if (header.getResizingAllowed() && (resizeIndex != -1)) {
  192.         hitColumn = columnModel.getColumn(resizeIndex);
  193.         if (hitColumn.getResizable()) {
  194.             // Resize it!
  195.             isResizing = true;
  196.             fireAction = false;
  197.             hitColumnIndex = resizeIndex;
  198.             originalWidth = hitColumn.getWidth();
  199.             widthDelta = 0;
  200.             header.setResizingColumn(hitColumn);
  201.             lastMouseX = p.x;
  202.             hitColumn.disableResizedPosting();
  203.         }
  204.         else
  205.             hitColumn = null;
  206.         }
  207.         else {
  208.         boolean controlKeyDown = e.isControlDown();
  209.             if (header.getReorderingAllowed() && headerRect.contains(p)) {
  210.             // Can't move if we are the only column in the table
  211.             okToReorder = (columnModel.getColumnCount() > 1);
  212.                 // If the control key is down then we don't want to
  213.                 // start a reorder operation
  214.             if (controlKeyDown) {
  215.                 okToReorder = false;
  216.                 fireAction = false;
  217.             }
  218.                 }
  219.  
  220.         JTable table = header.getTable();
  221.         // Handle Selection
  222.         if (columnModel.getColumnSelectionAllowed() &&
  223.                 headerRect.contains(p) && table != null) {
  224.             // PENDING(alan): do the alt selection thing
  225.             if (controlKeyDown) {
  226.             if (table.isColumnSelected(index)) {
  227.                 // Control down, and the hit column is ready selected
  228.                 // we will deselect
  229.                 table.removeColumnSelectionInterval(index,index);
  230.             }
  231.             else {
  232.                     table.addColumnSelectionInterval(index, index);
  233.             }
  234.             }
  235.             else {
  236.             table.setColumnSelectionInterval(index, index);
  237.             }
  238.         }
  239.         // Set up cache vars
  240.         hitColumnIndex = index;
  241.         header.setDraggedColumn(hitColumn);
  242.         header.setDraggedDistance(0);
  243.         lastMouseX = p.x;
  244.         realDraggedDistance = 0;
  245.         }
  246.     }
  247.     }
  248.  
  249.     public void mouseReleased(MouseEvent e) {
  250.     hasPress = false;
  251.  
  252.     if (isResizing) {
  253.         isResizing = false;
  254.         originalWidth = 0;
  255.         header.setResizingColumn(null);
  256.  
  257.         // We have to set the column's width back to the original
  258.         // pre-resize width, reenable resize notification posting,
  259.         // then set the width to the new width.  This way when
  260.         // the resize notification is posted to the column's listeners
  261.         // it will have the correct original size, rather than the
  262.         // last incremental change.
  263.         int newWidth = hitColumn.getWidth();
  264.         hitColumn.setWidth(originalWidth);
  265.         hitColumn.enableResizedPosting();
  266.         hitColumn.setWidth(newWidth);
  267.     }
  268.     else if (isReordering) {
  269.         isReordering = false;
  270.         originalWidth = widthDelta = 0;
  271.         realDraggedDistance = 0;
  272.  
  273.         //PENDING(alan)
  274.         // hitColumn.enableResizedPosting();
  275.     }
  276.     else if (fireAction) {
  277.         fireAction = false;
  278.  
  279.     }
  280.  
  281.     header.setDraggedColumn(null);
  282.     header.setDraggedDistance(0);
  283.  
  284.     // Repaint to finish cleaning up
  285.     header.repaint();
  286.     JTable table = header.getTable();
  287.     if (table != null)
  288.         table.repaint();
  289.  
  290.     // Reset local state
  291.     okToReorder = false;
  292.     hitColumnIndex = -1;
  293.     hitColumn = null;
  294.     }
  295.  
  296.     public void mouseEntered(MouseEvent e) {}
  297.     public void mouseExited(MouseEvent e) {}
  298.  
  299. //
  300. // Paint Methods and support
  301. //
  302.  
  303.     public void paint(Graphics g, JComponent c) {
  304.         JTableHeader header = (JTableHeader) c;
  305.     Rectangle paintBounds = g.getClipBounds(), intersection;
  306.         Dimension size = header.getSize();
  307.     Component component = null;
  308.  
  309.     if (header.getColumnModel() == null)
  310.         // Can't draw if I don't have a columnModel
  311.         return;
  312.  
  313.     // Paint the background first
  314.     Color bColor = header.getParent().getBackground();
  315.     if(bColor != null) {
  316.         g.setColor(bColor);
  317.         g.fillRect(paintBounds.x, paintBounds.y, paintBounds.width,
  318.                paintBounds.height);
  319.     }
  320.  
  321.  
  322.     // Calculate the inset for cell rect
  323.     Rectangle cellRect = new Rectangle(0,0,size.width,size.height);
  324.     /*Insets i = getInsets(header);
  325.  
  326.     cellRect.x += i.left;
  327.     cellRect.y += i.top;
  328.     cellRect.width -= (i.right + cellRect.x);
  329.     cellRect.height -= (i.bottom + cellRect.y);*/
  330.  
  331.     // Paint the non-dragged header cells first
  332.     int column = 0;
  333.     boolean drawn = false;
  334.     Rectangle draggedCellRect = null;
  335.     TableColumn aColumn, draggedColumnObject = null;
  336.     TableCellRenderer renderer;
  337.     int columnMargin = header.getColumnModel().getColumnMargin();
  338.     Enumeration enumeration = header.getColumnModel().getColumns();
  339.  
  340.     while (enumeration.hasMoreElements()) {
  341.         aColumn = (TableColumn)enumeration.nextElement();
  342.         cellRect.width = aColumn.getWidth() + columnMargin;
  343.         // Note: The header cellRect includes columnMargin so the
  344.         //         drawing of header cells will not have any gaps.
  345.  
  346.         if (cellRect.intersects(paintBounds)) {
  347.         drawn = true;
  348.         if (aColumn != header.getDraggedColumn()) {
  349.             renderer = aColumn.getHeaderRenderer();
  350.             component = renderer.getTableCellRendererComponent(
  351.                   header.getTable(), aColumn.getHeaderValue(),
  352. //                  header.getColumnModel().isColumnSelected(column),
  353.                               false, false, // Don't do header selection.
  354.                   -1, column);
  355.             rendererPane.add(component);
  356.             rendererPane.paintComponent(g,component, header, cellRect.x, cellRect.y,
  357.                                     cellRect.width, cellRect.height, true);
  358.         }
  359.         else {
  360.             // Draw a gray well in place of the moving column
  361.             g.setColor(header.getParent().getBackground());
  362.             g.fillRect(cellRect.x, cellRect.y,
  363.                    cellRect.width, cellRect.height);
  364.             draggedCellRect = new Rectangle(cellRect);
  365.             // draggedColumnObject = aColumn;
  366.         }
  367.         }
  368.         else {
  369.         if (drawn)
  370.             // Don't need to iterate through the rest
  371.             break;
  372.         }
  373.  
  374.         cellRect.x += cellRect.width;
  375.         column++;
  376.     }
  377.  
  378.     // draw the dragged cell if we are dragging
  379.     draggedColumnObject = header.getDraggedColumn();
  380.     if (draggedColumnObject != null && draggedCellRect != null) {
  381.         renderer = draggedColumnObject.getHeaderRenderer();
  382.         component = renderer.getTableCellRendererComponent(
  383.               header.getTable(), draggedColumnObject.getHeaderValue(),
  384. //              header.getColumnModel().isColumnSelected(column),
  385.                       false, false, // Don't do header selection.
  386.               -1, column);
  387.         draggedCellRect.x += header.getDraggedDistance();
  388.         SwingUtilities.paintComponent(g, component,header,draggedCellRect);
  389.     }
  390.     }
  391.  
  392. //
  393. // Size Methods
  394. //
  395.  
  396.     public Dimension getMinimumSize(JComponent c) {
  397.         return getPreferredSize(c);
  398.     }
  399.  
  400.     public Dimension getPreferredSize(JComponent c) {
  401.     JTableHeader header = (JTableHeader)c;
  402.     JTable table = header.getTable();
  403.  
  404.         // The preffered width of the header is the preferred width of the table.
  405.         Dimension tableSize = table.getPreferredSize();
  406.         Dimension size = new Dimension();
  407.         size.width = tableSize.width;
  408.         // Now compute the height.
  409.     int column = 0;
  410.     Enumeration enumeration = header.getColumnModel().getColumns();
  411.  
  412.     while (enumeration.hasMoreElements()) {
  413.         TableColumn aColumn = (TableColumn)enumeration.nextElement();
  414.  
  415.         // Compute the height
  416.         TableCellRenderer renderer = aColumn.getHeaderRenderer();
  417.         Component comp = renderer.getTableCellRendererComponent(header.getTable(),
  418.                            aColumn.getHeaderValue(), false, false,
  419.                            -1, column);
  420.         size.height = Math.max(size.height, comp.getPreferredSize().height);
  421.  
  422.         column++;
  423.     }
  424.     return size;
  425.     }
  426.  
  427.     public Dimension getMaximumSize(JComponent c) {
  428.         return getPreferredSize(c);
  429.     }
  430.  
  431. //
  432. // Protected & Private Methods
  433. //
  434.  
  435.     private void move(MouseEvent e) {
  436.     TableColumnModel columnModel = header.getColumnModel();
  437.     int width;
  438.     int lastColumn = columnModel.getColumnCount() - 1;
  439.  
  440.     // Compute how much we are moving and the total redraw rect
  441.     Rectangle redrawRect = header.getHeaderRect(hitColumnIndex);  // where I was
  442.     redrawRect.x += header.getDraggedDistance();
  443.     int delta = e.getX() - lastMouseX;
  444.     realDraggedDistance += delta;
  445.     Rectangle redrawRect2 = header.getHeaderRect(hitColumnIndex); // where I'm now
  446.     redrawRect2.x += realDraggedDistance;
  447.     redrawRect = redrawRect.union(redrawRect2);  // Union the 2 rects
  448.  
  449.     // Now check if we have moved enough to do a swap
  450.     if ((realDraggedDistance < 0) && (hitColumnIndex != 0)) {
  451.         // Moving left; check prevColumn
  452.         width = columnModel.getColumnMargin() +
  453.         columnModel.getColumn(hitColumnIndex-1).getWidth();
  454.         if (-realDraggedDistance > (width / 2)) {
  455.         // Swap me
  456.         columnModel.moveColumn(hitColumnIndex, hitColumnIndex-1);
  457.  
  458.         realDraggedDistance = width + realDraggedDistance;
  459.         hitColumnIndex--;
  460.         }
  461.     }
  462.     else if ((realDraggedDistance > 0) && (hitColumnIndex != lastColumn)) {
  463.         // Moving right; check nextColumn
  464.         width = columnModel.getColumnMargin() +
  465.         columnModel.getColumn(hitColumnIndex+1).getWidth();
  466.         if (realDraggedDistance > (width / 2)) {
  467.         // Swap me
  468.         columnModel.moveColumn(hitColumnIndex, hitColumnIndex+1);
  469.  
  470.         realDraggedDistance = -(width - realDraggedDistance);
  471.         hitColumnIndex++;
  472.         }
  473.     }
  474.  
  475.     // Set the draggedDistance before display
  476.     int draggedDistance = realDraggedDistance;
  477.     if (hitColumnIndex == 0) {
  478.         // I'm the left most column, so we can't have a negative
  479.         // draggedDistance
  480.         if (draggedDistance < 0)
  481.         draggedDistance = 0;
  482.     }
  483.     else if (hitColumnIndex == lastColumn) {
  484.         if (draggedDistance > 0)
  485.         draggedDistance = 0;
  486.     }
  487.     header.setDraggedColumn(columnModel.getColumn(hitColumnIndex));
  488.     header.setDraggedDistance(draggedDistance);
  489.  
  490.     // Redraw
  491.     header.repaint(redrawRect.x, 0, redrawRect.width, redrawRect.height);
  492.     if (header.getUpdateTableInRealTime()) {
  493.         JTable table = header.getTable();
  494.         if (table != null)
  495.         table.repaint(redrawRect.x, 0, redrawRect.width,
  496.                   (table.getRowHeight() +
  497.                    table.getIntercellSpacing().height)
  498.                   * table.getRowCount());
  499.     }
  500.     }
  501.  
  502.     private int getResizingColumn(Point p) {
  503.     int column = 0;
  504.     Rectangle resizeRect = new Rectangle(-3,0,6,header.getSize().height);
  505.     int columnMargin = header.getColumnModel().getColumnMargin();
  506.     Enumeration enumeration = header.getColumnModel().getColumns();
  507.  
  508.     while (enumeration.hasMoreElements()) {
  509.         TableColumn aColumn = (TableColumn)enumeration.nextElement();
  510.         resizeRect.x += aColumn.getWidth() + columnMargin;
  511.  
  512.         if (resizeRect.x > p.x) {
  513.         // Don't have to check the rest, we already gone past p
  514.         break;
  515.         }
  516.         if (resizeRect.contains(p))
  517.         return column;
  518.  
  519.         column++;
  520.     }
  521.     return -1;
  522.     }
  523.  
  524. }  // End of Class BasicTableHeaderUI
  525.  
  526.